/***************************************************************************
 *   Copyleft 2008-2009 by												   *
 *	 Iwanicki Krzysztof													   *
 *   <gamma.mini.pw.edu.pl/~iwanickik>									   *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 ***************************************************************************/
#ifndef __VSTRING_H__
#define __VSTRING_H__

#include <iostream>
#include <string>
#include <cctype>
#include <algorithm>
#include <Types/vTypes.h>
#include "../Macros/vMemoryMacros.h"

namespace Vendetta {
	class vString {
	public:
		static vUInt MaxPos;
		static const vString Blank;

	public:
		vString();
		explicit vString(std::string& str);
		explicit vString(const std::string& str);
		vString(const vString& str);
		vString(const vChar* str);
		vString(vChar* str);
		
		~vString();

		vString ToUpperCase();

		vString ToLowerCase();

		const vChar& operator[](vUInt pos) const;

		vChar& operator[](vUInt pos);

		const vChar& At(vUInt pos) const;
	    
		vChar& At(vUInt pos);
		
		inline vBool IsEmpty() const {
			return mData.empty();
		}

		inline vUInt Length() const {
			return static_cast<vUInt>(mData.length());
		}

		inline vString& operator=(const vString& str) {
			if (this != &str) {
				mData = str.mData;
			}

			return *this;
		}

		inline vString& operator=(const std::string& str) {
			mData = str;

			return *this;
		}

		inline vString& operator=(const vChar* str) {
			mData = str;

			return *this;
		}

		inline vString& operator+=(const vString& str) {
			mData += str.mData;

			return *this;
		}

		inline vString& operator+=(const std::string& str) {
			mData += str;

			return *this;
		}

		inline vString& operator+=(const vChar* s) {
			mData += s;

			return *this;
		}

		inline vString& operator+=(vChar c) {
			mData += c;

			return *this;
		}

		inline vString& operator<<(const vString& str) {
			mData += str.mData;

			return *this;
		}

		inline vString& operator<<(const std::string& str) {
			mData += str;

			return *this;
		}

		inline vString& operator<<(const vChar* str) {
			mData += str;

			return *this;
		}

		inline vString& operator<<(vChar str) {
			mData += str;

			return *this;
		}

		inline vString SubString(vUInt pos = 0, vUInt n = vString::MaxPos) const {
			return vString(mData.substr(pos, n));
		}

		inline vInt Compare(const vString& str) const {
			return mData.compare(str.mData);
		}

		inline vInt Compare(const vChar* s) const {
			return mData.compare(s);
		}

		inline vInt Compare(vUInt pos1, vUInt n1, const vString& str) const {
			return mData.compare(pos1, n1, str.mData);
		}

		inline vInt Compare(vUInt pos1, vUInt n1, const vChar* s) const {
			return mData.compare(pos1, n1, s);
		}

		inline vInt Compare(vUInt pos1, vUInt n1, const vString& str, vUInt pos2, vUInt n2) const {
			return mData.compare(pos1, n1, str.mData, pos2, n2);
		}

		inline vInt Compare(vUInt pos1, vUInt n1, const vChar* s, vUInt n2) const {
			return mData.compare(pos1, n1, s, n2);
		}

		inline vBool IsEqual(const vString& str) {
			return (mData.compare(str.mData) == 0);
		}

		inline vBool IsEqual(const char* str) {
			return (mData.compare(str) == 0);
		}

		inline vVoid Clear() {
			mData.clear();
		}
		
		inline const vChar* ToConstCharPtr() const {
			return mData.c_str();
		}

		inline const std::string ToStdString() const {
			return mData;
		}

		inline vUInt Find(const vString& str, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find(str.mData, pos));
		}

		inline vUInt Find(const vChar* s, vUInt pos, vUInt n) const {
			return static_cast<vUInt>(mData.find(s, pos, n));

		}

		inline vUInt Find(const vChar* s, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find(s, pos));

		}

		inline vUInt Find(vChar c, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find(c, pos));
		}

		inline vUInt ReverseFind(const vString& str, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.rfind(str.mData, pos));
		}

		inline vUInt ReverseFind(const vChar* s, size_t pos, vUInt n) const {
			return static_cast<vUInt>(mData.rfind(s, pos, n));
		}

		inline vUInt ReverseFind(const vChar* s, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.rfind(s, pos));
		}

		inline vUInt ReverseFind(vChar c, vUInt pos = vString::MaxPos )const {
			return static_cast<vUInt>(mData.rfind(c, pos));
		}

		inline vUInt FindFirstOf(const vString& str, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_of(str.mData, pos));
		}

		inline vUInt FindFirstOf(const vChar* s, vUInt pos, vUInt n) const {
			return static_cast<vUInt>(mData.find_first_of(s, pos, n));
		}

		inline vUInt FindFirstOf(const vChar* s, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_of(s, pos));
		}

		inline vUInt FindFirstOf(vChar c, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_of(c, pos));
		}

		inline vUInt FindLastOf(const vChar* s, vUInt pos, vUInt n) const {
			return static_cast<vUInt>(mData.find_last_of(s, pos, n));
		}

		inline vUInt FindLastOf(const vChar* s, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.find_last_of(s, pos));
		}

		inline vUInt FindLastOf(vChar c, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.find_last_of(c, pos));
		}

		inline vUInt FindFirstNotOf(const vString& str, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_not_of(str.mData, pos));
		}

		inline vUInt FindFirstNotOf(const vChar* s, vUInt pos, vUInt n) const {
			return static_cast<vUInt>(mData.find_first_not_of(s, pos, n));
		}

		inline vUInt FindFirstNotOf(const vChar* s, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_not_of(s, pos));
		}

		inline vUInt FindFirstNotOf(vChar c, vUInt pos = 0) const {
			return static_cast<vUInt>(mData.find_first_not_of(c, pos));
		}

		inline vUInt FindLastNotOf(const vString& str, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.find_last_not_of(str.mData, pos));
		}

		inline vUInt FindLastNotOf(const vChar* s, vUInt pos, vUInt n) const {
			return static_cast<vUInt>(mData.find_last_not_of(s, pos, n));
		}

		inline vUInt FindLastNotOf(const vChar* s, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.find_last_not_of(s, pos));
		}

		inline vUInt FindLastNotOf(vChar c, vUInt pos = vString::MaxPos) const {
			return static_cast<vUInt>(mData.find_last_not_of(c, pos));
		}

		inline vString& Erase(vUInt pos = 0, vUInt n = vString::MaxPos) {
			mData.erase(pos, n);

			return *this;
		}

		inline vString& Replace(vUInt pos1, vUInt n1, const vString& str) {
			mData.replace(pos1, n1, str.mData);

			return *this;
		}

		inline vString& Replace(vUInt pos1, vUInt n1, const vString& str, vUInt pos2, vUInt n2) {
			mData.replace(pos1, n1, str.mData, pos2, n2);

			return *this;
		}		

		friend vString operator+(const vString& str1, const vString& str2);
		
		friend vBool operator==(const vString& lhs, const vString& rhs);
		friend vBool operator==(const vChar* lhs, const vString& rhs);
		friend vBool operator==(const vString& lhs, const vChar* rhs);

		friend vBool operator!=(const vString& lhs, const vString& rhs);
		friend vBool operator!=(const vChar* lhs, const vString& rhs);
		friend vBool operator!=(const vString& lhs, const vChar* rhs);

		friend vBool operator<(const vString& lhs, const vString& rhs);
		friend vBool operator<(const vChar* lhs, const vString& rhs);
		friend vBool operator<(const vString& lhs, const vChar* rhs);

		friend vBool operator>(const vString& lhs, const vString& rhs);
		friend vBool operator>(const vChar* lhs, const vString& rhs);
		friend vBool operator>(const vString& lhs, const vChar* rhs);

		friend vBool operator<=(const vString& lhs, const vString& rhs);
		friend vBool operator<=(const vChar* lhs, const vString& rhs);
		friend vBool operator<=(const vString& lhs, const vChar* rhs);

		friend vBool operator>=(const vString& lhs, const vString& rhs);
		friend vBool operator>=(const vChar* lhs, const vString& rhs);
		friend vBool operator>=(const vString& lhs, const vChar* rhs);

		friend std::ostream& operator<<(std::ostream& out, const vString& str);

		friend std::istream& operator>>(std::istream& in, vString& str);

		friend std::istream& GetLine(std::istream& is, vString& str, vChar delim);
		friend std::istream& GetLine(std::istream& is, vString& str);

	private:
		std::string mData;
	};
}

#endif //__VSTRING_H__

